package socket.demo1;

import java.io.DataOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class Server extends Thread {
    private static ServerSocket server; //接收端
    private static int ServerPort = 9876; //端口号
    private int v_r = 0; //接收状态变量初始化

    //构造方法
    public static void main(String[] args) {
        (new Server()).start();
    }

    public void run() {
        Socket socket;
        ObjectInputStream in;

        System.out.println("服务端已启动");

        ServerSocket serverSocket = null;
        try {
            serverSocket = new ServerSocket(ServerPort);
        } catch (IOException e) {
            e.printStackTrace();
        }
        while (true) {
            try {
                // 与客户端连接。
                socket = serverSocket.accept();
                socket.setSoTimeout(10000); //设置超时定时器
                in = new ObjectInputStream(socket.getInputStream());
                Msg data = (Msg) in.readObject();//读取客户端发送的数据
                //判断是不是结束信号，如果是结束信号，则关闭服务端，并向客户端发送结束信号。如果不是结束信号，就根据客户端发来的数据状态恢回复对应的信息。
                if (data.getInfo().equals("over")) {
                    System.out.println("结束！服务端关闭");
                    DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
                    dos.writeBytes("over too!");
                    //相关对象置为空
                    dos.close();
                    while(!socket.isClosed()){
                        try{
                            Thread.sleep(1000);
                        }catch (Exception e){
                            e.printStackTrace();
                        }
                    }

                    break;
                } else {
                    System.out.println("客户端正在发送的数据:" + data.getStateValue());
                    if (data.getInfo().equals("DataError")) {//如果状态为数据错误，则丢失该分组，向客户端回复"NAK"，让客户端重新发送该分组。
                        System.out.println("状态：" + data.getInfo());
                        System.out.println("数据错误，丢失后重发");
                        DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
                        dos.writeBytes("NAK" + '\n');
                        dos.close();
                    } else if (v_r == data.getStateValue()) {//将接收端状态变量和客户端状态变量比较，如果相等则为不重复的分组，否则为重复的分组。
                        if (data.getInfo().equals("losePackage")) {//如果状态为数据丢失，向客户端回复""resend1""，让客户端重新发送该分组。
                            System.out.println("状态：" + data.getInfo());
                            System.out.println("数据丢失");
                            DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
                            dos.writeBytes("resend1" + '\n');
                            dos.close();
                        } else if (data.getInfo().equals("loseAck")) {
                            //如果状态为ACK丢失，向客户端回复""resend2""，让客户端重新发送该分组。
                            System.out.println("状态：" + data.getInfo());
                            System.out.println("ACK丢失");
                            DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
                            dos.writeBytes("resend2" + '\n');
                            dos.close();
                        } else {//如果状态为没有错误，向客户端回复"ACK"确认收到分组，让客户端重新发送该分组。
                            System.out.println("状态：" + data.getInfo());
                            System.out.println("接收分组 " + data.getStateValue() + "   发送ACK " + data.getStateValue());
                            DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
                            dos.writeBytes("ACK" + '\n');
                            dos.close();
                            v_r = (v_r + 1) % 2;//接受ACK后，将接收端状态信号加1。
                        }
                    } else {//如果是重复分组，直接将该分组丢失即可。向客户端发送ACK。
                        System.out.println("重复分组，丢失");
                        DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
                        dos.writeBytes("ACK" + '\n');
                        dos.close();
                    }
                }
            } catch (IOException e) {
                System.out.println("Socket连线有问题");
                System.out.println("IOException :" + e.toString());
            } catch (ClassNotFoundException e) {
                System.out.println("ClassNotFoundException :" + e.toString());
            }
        }
    }
}
